#ifndef RAWOBJECTDATA_H_
#define RAWOBJECTDATA_H_
#include <list>
#include "math/Vector3.h"
#include "Color.h"
#include "GLTexture.h"

using namespace std;
/*
*	___ RAWOBJECTDATA Header___
*
*
***************************************************************/

class TriangleData;


class VertexData
{
	private:
		Vector3* _p;
		Vector3* _normal;
		list<TriangleData*> _parent;
	public:
		VertexData( Vector3 *p );
		~VertexData( );
		void addParent( TriangleData *parent );
		void ClearParents();
		Vector3* getPoint( );
		void ComputeNormal();
		Vector3* getNormal();
		list<TriangleData*>* getParentList();
};

class TexCoordData
{
	private:
		float *_u, *_v;
	public:
		TexCoordData( const float& u, const float& v );
		~TexCoordData( );
		float* getU( ) const;
		float* getV( ) const;
		void RepeatUV(int xRepeat, int yRepeat);
	friend ostream & operator<< (ostream &o, const TexCoordData &tc);
};

class EdgeData
{
	private:
		TriangleData* _parent1;
		TriangleData* _parent2;
		VertexData *_p1;
		VertexData *_p2;
		Vector3*	 _normal;
		bool _smooth;
	public:
		EdgeData( VertexData* p1,VertexData* p2, TriangleData* parent1,TriangleData* parent2 );
		~EdgeData();
		VertexData* getP1();
		VertexData* getP2();
		TriangleData* getParent1() const;
		TriangleData* getParent2() const;
		Vector3*	getNormal() const;
		bool		isSmooth() const;
};

class MaterialData;

class TextureData
{
	private:
		string						_texID;
		unsigned int				_intTexID;
		int xRepeat;
		int yRepeat;
	public:
		TextureData( string texID );
		TextureData( string texID, int xRepeat, int yRepeat );
		~TextureData();
		string getTexID();
		int getIntTexID();
		void setIntTexID(unsigned int id);
		int getXRepeat();
		int getYRepeat();
};

class MaterialData
{
	private:
		string _matName;
		Color *_ambient;
		Color *_diffuse;
		Color *_specular;
		float *_transparancy;
		TextureData*	_texture;
	public:
		MaterialData( string matName, Color *ambient, Color *diffuse, Color *specular, float *transparancy, TextureData* texture );
		~MaterialData();
		string getMatName() const;
		Color* getAmbient( ) const;
		Color* getDiffuse( ) const;
		Color* getSpecular( ) const;
		float* getTransparancy( ) const;
		TextureData* getTexture( );
		friend ostream & operator<< (ostream &o, const MaterialData &mat);
};

class MeshData;

class TriangleData
{
	private:
		// 'modeFlags' represents different States of this Triangle
		// 8 bit
		//  |----------- BITS -----------|
		// 	 80	40	20	10	8	4	2	1 ( hex)
		//
		//	1	->	isCollisionDetection
		//	2	->	isInvisible
		//	4	->	isLightOff
		//	8	->	stayAtCamera
		//	10	->	lookAtCamera
		//	20	->	noCulling
		//	40	->	hasTextureImage
		//	80	->	isSmooth
		unsigned char	_modeFlags;
		bool 			_withTexture;
		VertexData*		_v1;
		VertexData*		_v2;
		VertexData*		_v3;
		EdgeData*		_edgeP1;
		EdgeData*		_edgeP2;
		EdgeData*		_edgeP3;
		Vector3*		_normal;
		TexCoordData*	_tc1;
		TexCoordData*	_tc2;
		TexCoordData*	_tc3;
		MaterialData*	_material;
		MeshData*		_parent;
		Vector3*		_middlePoint;


		TriangleData* findNeighbour( VertexData* p1, VertexData* p2 );
	public:
		TriangleData( 	VertexData *v1, VertexData *v2,VertexData *v3,
							TexCoordData *tc1, TexCoordData *tc2,TexCoordData *tc3,
							MaterialData *material, unsigned char flags );
		TriangleData( 	VertexData *v1, VertexData *v2,VertexData *v3,MaterialData *material, unsigned char flags );
		~TriangleData();
		void setParent( MeshData* mesh );
		MeshData* getParent( );

		Vector3* getMiddlePoint();
		VertexData* getP1();
		VertexData* getP2();
		VertexData* getP3();

		Vector3* getP1Normal() const;
		Vector3* getP2Normal() const;
		Vector3* getP3Normal() const;

		EdgeData* getEdge1();
		EdgeData* getEdge2();
		EdgeData* getEdge3();
		EdgeData* CreateEdge( VertexData* p1 ,VertexData* p2, TriangleData* parent2 );
		void CreateEdge( EdgeData*  edge );
		void setP1(VertexData* v);
		void setP2(VertexData* v);
		void setP3(VertexData* v);
		TexCoordData* getTexCoord1();
		TexCoordData* getTexCoord2();
		TexCoordData* getTexCoord3();
		MaterialData* getMaterial();
		void BindTexture();
		void UnbindTexture();
		bool isWithTexture();
		void ComputeNormal();
		void ComputeEdges();
		Vector3* getNormal() const;
		void setNormal(Vector3* no);
		bool IsTransparency() const;



		inline bool isCollision() const
		{
			return (_modeFlags & 0x1);
		};

		inline bool isInvisible() const
		{
			return (_modeFlags & 0x2);
		};

		inline bool isLightOff() const
		{
			return (_modeFlags & 0x4);
		};

		inline bool isStayingAtCam() const
		{
			return (_modeFlags & 0x8);
		};

		inline bool isLookingAtCam() const
		{
			return (_modeFlags & 0x10);
		};

		inline bool hasNoCulling() const
		{
			return (_modeFlags & 0x20);
		};

		inline bool hasTextureImage() const
		{
			return (_modeFlags & 0x40);
		};

		inline bool isSmooth() const
		{
			return (_modeFlags & 0x80);
		};
};


class RawObjectData;

class MeshData
{
	private:
		string _name;
		bool	_withTexture;
		RawObjectData* 		_parent;

		void DivideParents( list<VertexData*> *l );
	public:
		MeshData(string name);
		~MeshData();

		void setParent( RawObjectData* obj );
		RawObjectData* getParent( );
		void addTriangle( TriangleData* triangle );
		vector<TriangleData*> 	_triangles;
		vector<VertexData*>		_vertices;
		vector<Vector3*>		_normals;
		vector<TexCoordData*> 	_texCoords;
		vector<EdgeData*> 		_edges;
		long getPolygonCount();
		void RemoveRedundantVertices();
		void MergeVertices();
		bool isWithTexture();
};

class RawObjectData
{
	protected:
		string						_filename;
		GLTexture* 					_texturesLoader;
		vector<MeshData*>			_meshes;

		vector<MaterialData*> 	_materials;
		vector<TextureData*>		_textures;

		bool _checkRedundants;
		bool _isAlwaysVisible;

	public:
		RawObjectData( );
		virtual ~RawObjectData( );

		vector<MeshData*>* getMeshes();
		vector<MaterialData*>* getMaterials();
		vector<TextureData*>* getTextures();


		GLTexture* getTextureLoader();
		string getFilename();
		void addMesh(MeshData* mesh);
		long getPolygonCount();

		bool isCheckingRedundants();
		void setCheckingRedundants(bool rr);
		void setAllwaysVisible( bool value );
		bool isAlwaysVisible();

		virtual bool loadObject( string filename ) = 0;
};

/***************************************************************/
#endif

